namespace ClassyBlog.Web.Specs.Unit
{
    using System;
    using System.Linq;
    using System.Web.Mvc;

    using Machine.Specifications;
    using NSubstitute;

    using DataAccess;
    using DomainObjects;
    using ExtensionMethods;

    [Subject(typeof(PagesController))]
    public class when_creating_pages_controller_with_null_repository
    {
        static Exception exception;

        Because of = () =>
            exception = Catch.Exception(() => new PagesController(null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    public abstract class PagesControllerSpec
    {
        protected static Blog blog;
        protected static IPageRepository repository;
        protected static PagesController controller;

        Establish context = () =>
        {
            blog = ObjectMother.CreateBlog();
            blog.Merge(new { PagesPerPage = 5 });

            repository = Substitute.For<IPageRepository>();
            controller = new PagesController(repository);

            controller.SetBlog(blog);
        };
    }

    [Subject(typeof(PagesController))]
    public class when_listing_pages_by_path : PagesControllerSpec
    {
        protected static ViewResult result;
        protected static CategorizedPageList viewModel;

        Establish context = () =>
            repository.FindAll(
            Arg.Any<string>()).
            Returns(ObjectMother.CreatePages(25));

        Because of = () =>
        {
            result = (ViewResult)controller.Index(1, "foo/bar");
            viewModel = (CategorizedPageList)result.Model;
        };

        It should_render_default_view = () => result.ViewName.ShouldBeEmpty();

        It should_set_correct_page = () =>
            viewModel.CurrentPage.ShouldEqual(1);

        It should_set_correct_total = () => viewModel.Total.ShouldEqual(25);

        It should_set_correct_page_size = () =>
            viewModel.PageSize.ShouldEqual(blog.PagesPerPage);

        It should_set_correct_list = () => viewModel.List.ShouldNotBeEmpty();

        It should_set_correct_category = () =>
            viewModel.Category.Title.ShouldEqual("bar");
    }

    [Subject(typeof(PagesController))]
    public class when_listing_empty_pages : PagesControllerSpec
    {
        static HttpNotFoundResult result;

        Establish context = () =>
            repository.FindAll(
            Arg.Any<string>()).Returns(Enumerable.Empty<Page>());

        Because of = () =>
            result = controller.Index(1, null) as HttpNotFoundResult;

        It should_throw_404 = () => result.ShouldNotBeNull();
    }

    [Subject(typeof(PagesController))]
    public class when_showing_non_existent_page : PagesControllerSpec
    {
        static HttpNotFoundResult result;

        Establish context = () =>
            repository.FindOne(Arg.Any<string>()).Returns((Page)null);

        Because of = () =>
            result = controller.Show("foo") as HttpNotFoundResult;

        It should_throw_404 = () => result.ShouldNotBeNull();
    }

    [Subject(typeof(PagesController))]
    public class when_showing_existent_page : PagesControllerSpec
    {
        static Page page;
        static ViewResult result;

        Establish context = () =>
        {
            page = ObjectMother.CreatePage();
            repository.FindOne(Arg.Any<string>()).Returns(page);
        };

        Because of = () => result = controller.Show("about-us") as ViewResult;

        It should_return_view = () => result.ShouldNotBeNull();

        It should_set_page_as_view_model = () =>
            result.Model.To<ItemModel<Page>>().Item.ShouldBeTheSameAs(page);
    }
}